using Circus.CodeEditor;
using Circus.Syntax.Design;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Design;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
namespace Circus.Syntax.Lexer
{
	[DesignerCategory("Code"), ToolboxItem(false)]
	public class Lexer : Component
	{
		private Container components = null;
		private int updateCount = 0;
		private EventHandler notifyHandler;
		private LexScheme scheme;
		private int defaultState;
		private ParseTextEventArgs parseTextEventArgs;
		[Description("Occurs when text line is parsed, allowing to modify colors/styles information about the parsed line.")]
        public event ParseTextEvent Parse;
		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public virtual int UpdateCount
		{
			get
			{
				return this.updateCount;
			}
		}
		[Browsable(false)]
		public virtual string XmlScheme
		{
			get
			{
				string result;
				try
				{
					StringWriter stringWriter = new StringWriter();
					try
					{
						this.Scheme.SaveStream(stringWriter);
						result = stringWriter.ToString();
					}
					finally
					{
						stringWriter.Close();
					}
				}
				catch
				{
					result = string.Empty;
				}
				return result;
			}
			set
			{
				try
				{
					StringReader stringReader = new StringReader(value);
					try
					{
						this.scheme.LoadStream(stringReader);
						this.OnXmlSchemeChanged();
					}
					finally
					{
						stringReader.Close();
					}
				}
				catch
				{
				}
			}
		}
		[Category("Parser"), Description("Gets or sets default state of the \"Lexer\".")]
		public virtual int DefaultState
		{
			get
			{
				return this.defaultState;
			}
			set
			{
				if (this.defaultState != value)
				{
					this.defaultState = value;
					this.OnDefaultStateChanged();
				}
			}
		}
		[Category("Parser"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Editor("QWhale.Syntax.Design.SyntaxBuilderEditor, QWhale.Syntax", typeof(UITypeEditor)), TypeConverter(typeof(LexSchemeConverter))]
		public virtual LexScheme Scheme
		{
			get
			{
				return this.scheme;
			}
			set
			{
				this.scheme = value;
				this.OnSchemeChanged();
			}
		}
		
		protected virtual void OnDefaultStateChanged()
		{
			this.Update();
		}
		protected virtual void OnSchemeChanged()
		{
			this.Update();
		}
		protected virtual void OnXmlSchemeChanged()
		{
			this.Update();
		}
		public Lexer(IContainer container) : this()
		{
			container.Add(this);
		}
		public Lexer()
		{
			this.InitializeComponent();
			this.parseTextEventArgs = new ParseTextEventArgs();
			this.scheme = this.CreateLexScheme();
		}
		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (this.components != null)
				{
					this.components.Dispose();
				}
			}
			base.Dispose(disposing);
		}
		protected virtual LexScheme CreateLexScheme()
		{
			return new LexScheme(this);
		}
		private void InitializeComponent()
		{
			this.components = new Container();
		}
		public virtual int BeginUpdate()
		{
			this.updateCount++;
			return this.updateCount;
		}
		public virtual int EndUpdate()
		{
			this.updateCount--;
			if (this.updateCount == 0)
			{
				this.Update();
			}
			return this.updateCount;
		}
		public virtual int DisableUpdate()
		{
			this.updateCount++;
			return this.updateCount;
		}
		public virtual int EnableUpdate()
		{
			this.updateCount--;
			return this.updateCount;
		}
		public virtual void AddNotifier(INotifier sender)
		{
			this.notifyHandler = (EventHandler)Delegate.Combine(this.notifyHandler, new EventHandler(sender.Notification));
		}
		public virtual void RemoveNotifier(INotifier sender)
		{
			this.notifyHandler = (EventHandler)Delegate.Remove(this.notifyHandler, new EventHandler(sender.Notification));
		}
		public virtual void Update()
		{
			if (this.updateCount == 0)
			{
				this.Notify(EventArgs.Empty);
			}
		}
		public virtual void Notify(EventArgs e)
		{
			if (this.notifyHandler != null)
			{
				this.notifyHandler(this, e);
			}
		}
		private void StateFromMatch(Match match, string s, Dictionary<int, LexSyntaxBlock> blocks, ref int state, ref int style)
		{
			style = -1;
			LexSyntaxBlock lexSyntaxBlock = null;
			for (int i = 0; i < match.Groups.Count; i++)
			{
				if (match.Groups[i].Success)
				{
					if (blocks.ContainsKey(i))
					{
						lexSyntaxBlock = blocks[i];
						break;
					}
				}
			}
			if (lexSyntaxBlock != null)
			{
				if (lexSyntaxBlock.LeaveState != null)
				{
					state = lexSyntaxBlock.LeaveState.Index;
				}
				if (lexSyntaxBlock.Style != null)
				{
					style = lexSyntaxBlock.Style.Index;
				}
				int i = lexSyntaxBlock.FindResword(s);
				if (i >= 0)
				{
					LexStyle reswordStyle = lexSyntaxBlock.ReswordSets[i].ReswordStyle;
					if (reswordStyle != null)
					{
						style = reswordStyle.Index;
					}
				}
			}
		}
		protected void OnTextParsed(string str, ref StringItemInfo[] colorData)
		{
			if (this.Parse != null)
			{
				this.parseTextEventArgs.String = str;
				this.parseTextEventArgs.ColorData = colorData;
				this.Parse(this, this.parseTextEventArgs);
			}
		}
		public virtual int ParseText(int state, int line, string str, ref StringItemInfo[] colorData)
		{
			int result;
			if (str == null || str == string.Empty)
			{
				result = state;
			}
			else
			{
				int length = str.Length;
				if (this.scheme.States.Count == 0)
				{
					for (int i = 0; i < length; i++)
					{
						colorData[i].Data = 0;
						colorData[i].TextStyle = TextStyle.None;
					}
					this.OnTextParsed(str, ref colorData);
					result = state;
				}
				else
				{
					LexState lexState = this.scheme.States[state];
					Match match = lexState.Regex.Match(str);
					int num = 0;
					int num2 = 0;
					int num3 = 0;
					while (match.Success)
					{
						if (match.Index > num)
						{
							for (int i = num; i < match.Index; i++)
							{
								colorData[i].Data = 0;
								colorData[i].TextStyle = TextStyle.None;
							}
						}
						num = match.Index;
						this.StateFromMatch(match, str.Substring(num, match.Length), lexState.Blocks, ref num2, ref num3);
						if (match.Length > 0)
						{
							for (int i = num; i < num + match.Length; i++)
							{
								colorData[i].Data = (byte)(num3 + 1);
							}
						}
						num += match.Length;
						if (num2 != state)
						{
							state = num2;
							lexState = this.scheme.States[num2];
							match = lexState.Regex.Match(str, num);
						}
						else
						{
							match = match.NextMatch();
						}
					}
					for (int i = num; i < length; i++)
					{
						colorData[i].Data = 0;
						colorData[i].TextStyle = TextStyle.None;
					}
					this.OnTextParsed(str, ref colorData);
					result = state;
				}
			}
			return result;
		}
		public virtual int ParseText(int state, int line, string str, ref int pos, ref int len, ref int style)
		{
			len = 0;
			style = 0;
			int result;
			if (str == null)
			{
				result = state;
			}
			else
			{
				LexState lexState = this.scheme.States[state];
				Match match = lexState.Regex.Match(str, pos);
				if (match.Success)
				{
					pos = match.Index;
					len = match.Length;
					int num = state;
					int num2 = 0;
					this.StateFromMatch(match, str.Substring(pos, len), lexState.Blocks, ref num, ref style);
					bool flag = pos + match.Length >= str.Length;
					int startat = flag ? (pos + match.Length) : pos;
					while (match.Length == 0 || flag)
					{
						if (state != num)
						{
							state = num;
							lexState = this.scheme.States[state];
							match = lexState.Regex.Match(str, startat);
						}
						else
						{
							match = match.NextMatch();
						}
						if (!match.Success)
						{
							break;
						}
						if (!flag)
						{
							pos = match.Index;
							len = match.Length;
						}
						this.StateFromMatch(match, string.Empty, lexState.Blocks, ref num, ref num2);
						if (!flag)
						{
							style = num2;
						}
					}
					state = num;
				}
				if (len == 0)
				{
					len = 1;
				}
				result = state;
			}
			return result;
		}
		public virtual void ResetDefaultState()
		{
			this.DefaultState = 0;
		}
		public virtual string RemovePlainText(string s, StringItemInfo[] textData)
		{
			string text = string.Empty;
			for (int i = 0; i < s.Length; i++)
			{
				text += (this.scheme.IsPlainText((int)(textData[i].Data - 1)) ? ' ' : s[i]);
			}
			return text;
		}
	}
}
